﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.SqlClient;
using System.Security.Cryptography;
using System.Data;

namespace DoeObjects
{
    public class Loan
    {



        #region attributes
        /// <summary>
        /// contains the loanId
        /// </summary>
        public int LoanId { get; set; }

        /// <summary>
        /// contains the Id of the loanable which is borrowed
        /// </summary>
        public Loanable Loanable { get; set; }

        /// <summary>
        /// contains the id of the user which borrowed this loanable
        /// </summary>
        public User Borrower { get; set; }

        /// <summary>
        /// the date(datetime) when the loanable was borrowed
        /// </summary>
        public DateTime BorrowDate { get; set; }
        
        /// <summary>
        /// the date when the loanable was returned. Since DateTime can't be null, the nullalias is DateTime.MinValue (ie when the loanable is still not returned)
        /// </summary>
        public DateTime ReturnDate { get; set; }

        /// <summary>
        /// the date when the loanable has to be returned. If the loan is renewed, this field will be updated
        /// </summary>
        public DateTime ToBeReturnedDate { get; set; }

        ///// <summary>
        ///// The owner of the loanable. //removed because this information is in the loanable object
        ///// </summary>
        //public User Owner { get; set; }

		public DateTime? RecallExpiredDate { get; set; }

        public RecallReason? ReasonForRecall { get; set; }

        #endregion

        private const string BASE_SQL = @"
SELECT * FROM Loan
INNER JOIN Loanable 
ON Loan.LoanableId = Loanable.LoanableId
INNER JOIN Title 
ON Loanable.TitleId = Title.TitleId 
INNER JOIN Publisher 
ON Title.PublisherId = Publisher.PublisherId 
INNER JOIN LoanableCategory 
ON Loanable.LoanableCategoryId = LoanableCategory.LoanableCategoryId 
INNER JOIN [User] 
ON Loanable.LoanableOwner = [User].UserId
INNER JOIN [UserCategory]
ON [User].CategoryId = [UserCategory].UserCategoryId
";

        /// <summary>
        /// returns the loan with the given loanId
        /// </summary>
        /// <param name="loanId"></param>
        /// <returns></returns>
        public static Loan getLoan(int loanId)
        {
            SqlParameter loanIdParameter = new SqlParameter("loanId", SqlDbType.Int);
            loanIdParameter.Value = loanId;

            SqlConnection connection = new SqlConnection(Settings.ConnectionString);
            SqlCommand command = new SqlCommand(BASE_SQL + " WHERE loan.loanId = @loanId", connection);
            command.Parameters.Add(loanIdParameter);

            Loan loan = null;
            try
            {
                connection.Open();

                SqlDataReader reader = command.ExecuteReader();
                if (reader.Read())
                {
                    loan = getCurrentLoan(reader, connection);
                }
                reader.Close();
            }
            catch (SqlException ex)
            {
                //something bad happened.
                //TODO: log exception
            }
            finally
            {
                if (connection != null && connection.State != ConnectionState.Closed)
                {
                    connection.Close();
                }
            }
            return loan;
        }

        /// <summary>
        /// returns a list of all loans from the loanable
        /// </summary>
        /// <param name="loanableId"></param>
        /// <returns></returns>
        public static List<Loan> getLoansFromLoanable(int loanableId)
        {
            List<Loan> loans = new List<Loan>();

            SqlConnection connection = new SqlConnection(Settings.ConnectionString);
            SqlCommand cmd = new SqlCommand(BASE_SQL + " WHERE loanable.loanableId = @loanableId", connection);
            cmd.Parameters.AddWithValue("@loanableId", loanableId);

            try
            {
                connection.Open();
                SqlDataReader reader = cmd.ExecuteReader();
                while (reader.Read())
                {
                    loans.Add(getCurrentLoan(reader, connection));
                }
                reader.Close();
            }
            catch (SqlException er)
            {
                //oo
                throw er;
            }
            finally
            {
                if (connection != null && connection.State != ConnectionState.Closed)
                {
                    connection.Close();
                }
            }

            return loans;
        }

        /// <summary>
        /// returns all Loans which belong to a loanable of the given user. It does NOT return the loan from a specifiy user
        /// </summary>
        /// <param name="ownerId"></param>
        /// <returns></returns>
        public static List<Loan> getLoansFromOwner(int ownerId)
        {
            List<Loan> loans = new List<Loan>();

            SqlConnection connection = new SqlConnection(Settings.ConnectionString);
            SqlCommand cmd = new SqlCommand(BASE_SQL + " WHERE loanable.loanableOwner = @ownerId", connection);
            cmd.Parameters.AddWithValue("@ownerId", ownerId);

            try
            {
                connection.Open();
                SqlDataReader reader = cmd.ExecuteReader();
                while (reader.Read())
                {
                    loans.Add(getCurrentLoan(reader, connection));
                }
                reader.Close();
            }
            catch (SqlException er)
            {
                //oo
                throw er;
            }
            finally
            {
                if (connection != null && connection.State != ConnectionState.Closed)
                {
                    connection.Close();
                }
            }

            return loans;
        }

        /// <summary>
        /// returns all borrows of the given user
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public static List<Loan> getLoansFromUser(int borrowerId)
        {
            List<Loan> loans = new List<Loan>();

            SqlConnection connection = new SqlConnection(Settings.ConnectionString);
            SqlCommand cmd = new SqlCommand(BASE_SQL + " WHERE borrower = @borrowerId", connection);
            cmd.Parameters.AddWithValue("@borrowerId", borrowerId);

            try
            {
                connection.Open();
                SqlDataReader reader = cmd.ExecuteReader();
                while (reader.Read())
                {
                    loans.Add(getCurrentLoan(reader, connection));
                }
                reader.Close();
            }
            catch (SqlException er)
            {
                //oo
                throw er;
            }
            finally
            {
                if (connection != null && connection.State != ConnectionState.Closed)
                {
                    connection.Close();
                }
            }

            return loans;
        }

        public static List<Loan> getActiveLoansFromUser(int borrowerId)
        {
            List<Loan> loans = new List<Loan>();

            SqlConnection connection = new SqlConnection(Settings.ConnectionString);
            SqlCommand cmd = new SqlCommand(BASE_SQL + " WHERE borrower = @borrowerId AND ReturnDate IS NULL", connection);
            cmd.Parameters.AddWithValue("@borrowerId", borrowerId);

            try
            {
                connection.Open();
                SqlDataReader reader = cmd.ExecuteReader();
                while (reader.Read())
                {
                    loans.Add(getCurrentLoan(reader, connection));
                }
                reader.Close();
            }
            catch (SqlException er)
            {
                //oo
                throw er;
            }
            finally
            {
                if (connection != null && connection.State != ConnectionState.Closed)
                {
                    connection.Close();
                }
            }

            return loans;
        }


        /// <summary>
        /// adds a new loan to the database and returns the new Id of the loan. Returns 0 if the insert failed
        /// </summary>
        /// <param name="loan"></param>
        /// <returns>Last inserted ID</returns>
        public static int add(Loan loan)
        {
            int lastInsertedId = 0;


            DateTime endOfSemester = SemesterDateHelper.getEndOfCurrentSemester().Date;
            DateTime actuallToBeReturnDate = Loan.getToBeReturnedDateForUserCategory(loan.Borrower.Category, DateTime.Now);
            DateTime toBeRetunedDate = (actuallToBeReturnDate.Date > endOfSemester) ? endOfSemester : actuallToBeReturnDate;

            SqlConnection connection = new SqlConnection(Settings.ConnectionString);
            SqlCommand cmd = new SqlCommand("INSERT INTO loan (LoanableId, Borrower, BorrowDate, ReturnDate, ToBeReturned, RecallReason) OUTPUT INSERTED.loanId VALUES (@LoanableId, @BorrowerId, @BorrowDate, NULL, @ToBeReturnedDate, @recallReason)", connection);
            cmd.Parameters.AddWithValue("@LoanableId", loan.Loanable.LoanableId);
            cmd.Parameters.AddWithValue("@BorrowerId", loan.Borrower.UserId);
            cmd.Parameters.AddWithValue("@BorrowDate", DateTime.Now);
            cmd.Parameters.AddWithValue("@ToBeReturnedDate", toBeRetunedDate);

            if (loan.ReasonForRecall == null) cmd.Parameters.AddWithValue("@recallReason", DBNull.Value);
            else cmd.Parameters.AddWithValue("@recallReason", (int)loan.ReasonForRecall);

            try
            {
                connection.Open();
                Object res = cmd.ExecuteScalar();
                if (res != null)
                {
                    lastInsertedId = (int)res;
                }
            }
            catch (SqlException er)
            {
                //oo
                throw er;
            }
            finally
            {
                if (connection != null && connection.State != ConnectionState.Closed)
                {
                    connection.Close();
                }
            }

            return lastInsertedId;
        }

        /// <summary>
        /// returns the date when a loan must be returned base on the usercategory
        /// </summary>
        /// <param name="category"></param>
        /// <param name="borrowDate"></param>
        /// <returns></returns>
        private static DateTime getToBeReturnedDateForUserCategory(UserCategory category, DateTime borrowDate)
        {
            switch (category.CategoryId)
            {
                case 1:
                    DateTime returnDate = new DateTime(borrowDate.Year, 6, 30, 23, 59, 59, DateTimeKind.Unspecified);
                    if (returnDate < borrowDate)
                    {
                        //we are already in the 2nd semester of the year
                        returnDate.AddMonths(6);
                        returnDate.AddDays(1); //because the init. was with 30 days (june has only 30 days)
                    }
                    return returnDate;
                default:
                    return borrowDate.AddDays(category.LoanPeriod);
            }
        }

        /// <summary>
        /// updates an existing loan in the database
        /// </summary>
        /// <param name="loan"></param>
        /// <returns></returns>
        public static bool update(Loan loan)
        {
            int affectedRows = 0;

            SqlConnection connection = new SqlConnection(Settings.ConnectionString);
            SqlCommand cmd = new SqlCommand("UPDATE loan SET LoanableId = @LoanableId, Borrower = @Borrower, BorrowDate = @BorrowDate, ReturnDate = @ReturnDate, ToBeReturned = @ToBeReturnedDate, RecallExpiredDate = @RecallExpiredDate, RecallReason = @recallReason WHERE loanId = @LoanId", connection);
            cmd.Parameters.AddWithValue("@LoanId", loan.LoanId);
            cmd.Parameters.AddWithValue("@LoanableId", loan.Loanable.LoanableId);
            cmd.Parameters.AddWithValue("@Borrower", loan.Borrower.UserId);
            cmd.Parameters.AddWithValue("@BorrowDate", loan.BorrowDate);
            cmd.Parameters.AddWithValue("@ReturnDate", (loan.ReturnDate == DateTime.MinValue)?DBNull.Value:(object)loan.ReturnDate);
            cmd.Parameters.AddWithValue("@ToBeReturnedDate", loan.ToBeReturnedDate);
			if (loan.RecallExpiredDate != null) cmd.Parameters.AddWithValue("@RecallExpiredDate", loan.RecallExpiredDate);
            else cmd.Parameters.AddWithValue("@RecallExpiredDate", DBNull.Value);

            if (loan.ReasonForRecall == null) cmd.Parameters.AddWithValue("@recallReason", DBNull.Value);
            else cmd.Parameters.AddWithValue("@recallReason", (int)loan.ReasonForRecall);

            try
            {
                connection.Open();
                affectedRows = cmd.ExecuteNonQuery();
            }
            catch (SqlException er)
            {
                //oo
                throw er;
            }
            finally
            {
                if (connection != null && connection.State != ConnectionState.Closed)
                {
                    connection.Close();
                }
            }

            return (affectedRows > 0);
        }

        public static Loan getLoanFromUserIdAndLoanableId(int usrID, int lnblID)
        {
            SqlConnection connection = new SqlConnection(Settings.ConnectionString);
            SqlCommand cmd = new SqlCommand(BASE_SQL + " WHERE borrower = @borrowerId AND Loan.LoanableId = @loanableId AND Loan.ReturnDate IS NULL", connection);
            cmd.Parameters.AddWithValue("@borrowerId", usrID);
            cmd.Parameters.AddWithValue("@loanableId", lnblID);
            Loan loan = null;

            try
            {
                connection.Open();
                SqlDataReader reader = cmd.ExecuteReader();
                if (reader.Read())
                {
                    loan = getCurrentLoan(reader, connection);
                }
                reader.Close();
            }
            catch (SqlException er)
            {
                //oo
                throw er;
            }
            finally
            {
                if (connection != null && connection.State != ConnectionState.Closed)
                {
                    connection.Close();
                }
            }

            return loan;
        }

        /// <summary>
        /// returns a loanobject out of a reader which contains loaninformation
        /// </summary>
        /// <param name="reader"></param>
        /// <returns></returns>
        internal static Loan getCurrentLoan(SqlDataReader reader, SqlConnection connection)
        {
            Loan loan = null;
            if (reader != null)
            {
                loan = new Loan();

                loan.LoanId = Convert.ToInt32(reader["LoanId"]);
                loan.Loanable = Loanable.getCurrentLoanable(reader, connection);// Convert.ToInt32(reader["LoanableId"]);
                loan.Borrower = User.getUserByUserId((int)reader["Borrower"], connection);
                loan.BorrowDate = (DateTime)reader["BorrowDate"];
                loan.ReturnDate = (reader["ReturnDate"] == DBNull.Value) ? DateTime.MinValue : (DateTime)reader["ReturnDate"];
                loan.ToBeReturnedDate = (DateTime)reader["ToBeReturned"];
                if (reader["RecallExpiredDate"] == DBNull.Value) loan.RecallExpiredDate = null;
                else loan.RecallExpiredDate = (DateTime)reader["RecallExpiredDate"];
                //loan.Owner = User.getUserByUserId((int)reader["LoanableOwner"], connection);

                if (reader["RecallReason"] == DBNull.Value)
                {
                    loan.ReasonForRecall = null;
                }
                else
                {
                    loan.ReasonForRecall = (RecallReason)((int)reader["RecallReason"]);
                }
            }

            return loan;
        }


        /// <summary>
        /// saves the current object. If it is a new object (LoanId == 0) the it adds it and sets the LoanId. Otherwise an update will be executed
        /// </summary>
        /// <returns>If the update/insert was successful</returns>
        public bool save()
        {
            if (this.LoanId == 0)
            {
                this.LoanId = Loan.add(this); //set the created id
                return (this.LoanId != 0);
            }
            else
            {
                return Loan.update(this);
            }
        }

        /// <summary>
        /// checks a loan in again. --> sets the ReturnDate to the current timestamp
        /// </summary>
        /// <param name="loanId"></param>
        /// <returns></returns>
        public bool checkIn()
        {
            //check if loan exists
            if (this.LoanId == 0)
                return false;

            //check if already checkedIn
            if (this.ReturnDate != DateTime.MinValue)
                return true;

            //everything ok --> do it :)
            SqlConnection connection = new SqlConnection(Settings.ConnectionString);
            SqlCommand cmd = new SqlCommand("UPDATE loan SET ReturnDate = GETDATE() WHERE loanId = @loanId", connection);
            cmd.Parameters.AddWithValue("@loanId", this.LoanId);
            int affectedRows = 0;

            try
            {
                connection.Open();
                affectedRows = cmd.ExecuteNonQuery();
                if (Title.isReserved(this.Loanable.Title.TitleId, false))
                {
                    //Notify next reservation that book is avalibe
                    //And set Avalible Date

                    Reservation nextReservation = Reservation.getNext(this.Loanable.Title.TitleId, false);
                    nextReservation.LoanRecalled = true;
                    nextReservation.AvailableDate = DateTime.Now;

                    if (nextReservation.save()) //if it doesn't work, we have a problem :)
                    {
                        Notification notification = new Notification();
                        notification.Recipient = nextReservation.User;
                        notification.Message = string.Format("You reserved {0}. This book is now available for you. Please pick it up till {1}", nextReservation.Title.BookTitle, nextReservation.AvailableDate.AddDays(Reservation.RESERVATION_EXPIRES_TIMER_IN_DAYS).ToShortDateString());
                        notification.Type = NotificationType.TITLE_RESERVATION;
                        notification.save();
                    }
                }
            }
            catch (SqlException er)
            {
                //oo
                throw er;
            }
            finally
            {
                if (connection != null && connection.State != ConnectionState.Closed)
                {
                    connection.Close();
                }
            }

            return (affectedRows > 0);
        }

        /// <summary>
        /// Checks Database for expired loans and returns
        /// them as a list.
        /// </summary>

        public static List<Loan> getExpiredLoans()
        {
  
            List<Loan> Results = new List<Loan>();
            // SQL = SELECT * FROM Loan WHERE ReturnDate > GETDATE();

            SqlConnection connection = new SqlConnection(Settings.ConnectionString);
            SqlCommand command = new SqlCommand(BASE_SQL + " WHERE ReturnDate is null AND ToBeReturned < GETDATE ( )", connection);

            try
            {
                connection.Open();

                SqlDataReader reader = command.ExecuteReader();
                while (reader.Read())
                {
                    Results.Add(getCurrentLoan(reader, connection));
                }
                reader.Close();
            }
            catch (SqlException ex)
            {
                //something bad happened.
                //TODO: log exception
            }
            finally
            {
                if (connection != null && connection.State != ConnectionState.Closed)
                {
                    connection.Close();
                }
            }
            return Results;

        }
        /// <summary>
        /// Handles all expired loans by renewing them if no reservations or if there are reservations notifies the person to bring it back and sets loan recalled for reservation that has been made.
        /// </summary>
        public static void handleExpiredLoans()
        {
            List<Loan>expiredLoans = getExpiredLoans();

            //For each loan check if there is a reservations
                //If True: Then store in loans with reservations
                //If False: Renew and Notify User

            //For each loan with reservations 
            //List<Loan> loanWithReservations = new List<Loan>();

            /*foreach (int titleId in loanWithReservations.Select(l => l.Loanable.Title.TitleId).Distinct().ToList())
            {
                List<Loan> loansFromThisTitle = loanWithReservations.Where(l => l.Loanable.Title.TitleId == titleId).ToList();

                int numberOfReservationsForThisTitle = Reservation.getReservations(titleId).Count;

                for (int i = 0; i < numberOfReservationsForThisTitle; i++)
                {
                    //get the oldest loan for this title and call it back
                }

            }*/

            //;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

            List<Loan>OrderedLoans = expiredLoans.OrderBy(loan => loan.BorrowDate).ToList();

            foreach (Loan loan in OrderedLoans)
            {
				if (loan.RecallExpiredDate.HasValue && loan.RecallExpiredDate.Value.AddDays(7) < DateTime.Now) 
                {
                    handleExpiredRecalls(loan);
                }
				else
                {
					if (Title.isReserved(loan.Loanable.Title.TitleId, false))
					{
                        loan.recall(RecallReason.RESERVATION);
						loan.RecallExpiredDate = DateTime.Now;
						update(loan);
                    
                        Reservation nextReservation = Reservation.getNext(loan.Loanable.Title.TitleId, false);
                        nextReservation.LoanRecalled = true;
                        nextReservation.save();
                    }
                    else
                    {
                        loan.renew();
                    }
				}
            }
        }

        /// <summary>
        /// Sends notification to user that book has been recalled for the reason provieded
        /// </summary>
        public void recall(RecallReason reason)
        {
            recall(reason, DateTime.Now.AddDays(7));
        }

        /// <summary>
        /// Use to recall a loan
        /// </summary>
        /// <param name="reason">Reason for what the book is being recalled. I.E. owner wants it back or on hold</param>
        /// <param name="RecalledDate">Date the book is recalled it not today</param>
        public void recall(RecallReason reason, DateTime RecalledDate)
        {
            if (reason == RecallReason.OWNER_RECALL)
            {
                //check if already recalled cause of a reservation and if so unset loanRecalled of latest reservation in queue
                if (this.ReasonForRecall.HasValue && this.ReasonForRecall.Value == RecallReason.RESERVATION)
                {
                    Reservation lastInQueue = Reservation.getLatestRecalledInReservationQueue(this.Loanable.Title.TitleId);
                    lastInQueue.LoanRecalled = false;
                    lastInQueue.save();
                }
            }

            //update loan
            this.ReasonForRecall = reason;
            this.RecallExpiredDate = RecalledDate;
            this.save();

            //send notification
            Notification BookRecalled = new Notification();
            BookRecalled.Recipient = this.Borrower;
            BookRecalled.Message = "Your book " + this.Loanable.Title.BookTitle + " has been recalled. Please return as soon as possible!";
            BookRecalled.Type = NotificationType.RECALL;
            BookRecalled.save();
        }

        /// <summary>
        /// returns the current loan for this loanable (if there is one :) )
        /// </summary>
        /// <param name="loanableId"></param>
        /// <returns></returns>
        public static Loan getCurrentActiveLoanForLoanable(int loanableId)
        {
            SqlConnection connection = new SqlConnection(Settings.ConnectionString);
            SqlCommand cmd = new SqlCommand(BASE_SQL + " WHERE ReturnDate IS NULL AND loan.loanableId = @loanableId", connection);
            cmd.Parameters.AddWithValue("@loanableId", loanableId);

            Loan loan = null;

            try
            {
                connection.Open();
                SqlDataReader reader = cmd.ExecuteReader();
                if (reader.Read())
                {
                    loan = getCurrentLoan(reader, connection);
                }
                reader.Close();
            }
            catch (SqlException er)
            {
                //oo
                throw er;
            }
            finally
            {
                if (connection != null && connection.State != ConnectionState.Closed)
                {
                    connection.Close();
                }
            }

            return loan;
        }

        /// <summary>
        /// Adds 7 days to the toBeReturnedDate and saves the loan. Then notifys user that loan has been renewed.
        /// </summary>
        private void renew()
        {

            Notification BookRenewedNotification = new Notification();
            BookRenewedNotification.Type = NotificationType.LOAN_RENEWED;
            BookRenewedNotification.Recipient = this.Borrower;

            DateTime endOfSemester = SemesterDateHelper.getEndOfCurrentSemester().Date;
            DateTime toBeRetunedDate;
            if (this.ToBeReturnedDate.Date > endOfSemester)
            {
                toBeRetunedDate = endOfSemester;
                BookRenewedNotification.Message = "Your book " + this.Loanable.Title.BookTitle + " has been auto-renewed for the end of the semester";
            }
            else
            {
                toBeRetunedDate = this.ToBeReturnedDate.AddDays(7);
                BookRenewedNotification.Message = "Your book " + this.Loanable.Title.BookTitle + " has been auto-renewed for 7 days";
            }

            this.save();

            BookRenewedNotification.save();
        }

        /// <summary>
        /// returns if the user has currently a loan with the given title
        /// </summary>
        /// <param name="titleId"></param>
        /// <param name="userId"></param>
        /// <returns></returns>
        public static bool userHasActiveLoanForTitle(int titleId, int userId)
        {
            int activeLoansWithTitle = 0;
            SqlConnection connection = new SqlConnection(Settings.ConnectionString);
            SqlCommand cmd = new SqlCommand("SELECT COUNT(*) FROM loan INNER JOIN loanable ON loan.loanableId = loanable.loanableId WHERE titleId = @titleId AND borrower = @userId AND ToBeReturned IS NULL", connection);
            cmd.Parameters.AddWithValue("@titleId", titleId);
            cmd.Parameters.AddWithValue("@userId", userId);

            try
            {
                connection.Open();
                activeLoansWithTitle = (int)cmd.ExecuteScalar();
            }
            catch (SqlException er)
            {
                //oo
                throw er;
            }
            finally
            {
                if (connection != null && connection.State != ConnectionState.Closed)
                {
                    connection.Close();
                }
            }

            return (activeLoansWithTitle > 0);
        }

		/// <summary>
		/// Notifys owner and user that his book/reserved book has not been returned 
		/// </summary>
		public static void handleExpiredRecalls(Loan loan)
		{ 
            if(loan.ReasonForRecall.Value == RecallReason.RESERVATION) 
            {
                //get latest reservation and unset loanRecalled field
                Reservation latestReservation = Reservation.getLatestRecalledInReservationQueue(loan.Loanable.Title.TitleId);
                if (latestReservation != null)
                {
                    latestReservation.LoanRecalled = false;
                    latestReservation.save();
                }
            }

			//Notify book owner
			Notification notification = new Notification();
			User userOwner = User.getUserByUserId(loan.Loanable.Owner.UserId);
			notification.Recipient = userOwner;
			notification.Message = string.Format("{0} {1} has failed to return a loanable of your title ({2}).", loan.Borrower.FirstName, loan.Borrower.LastName, loan.Loanable.Title);
			notification.Type = NotificationType.EXPIRED_RECALL;
			notification.save();

			//Delete bad users reservations
			//notify user that hi's/her's reservations has been removed as punishment for not returning book
			//and should return the book
			Notification notificationUser = new Notification();
			User user = User.getUserByUserId(loan.Borrower.UserId);
			notificationUser.Recipient = user;

			if (Reservation.deleteUserReservations(loan.Borrower.UserId))
				notificationUser.Message = string.Format("You have failed to return a book that was recalled. Therefore all your reservations has been deleted. Please return the book!");
			else
				notificationUser.Message = string.Format("You have failed to return a book that was recalled. Please return the book!");

			notificationUser.Type = NotificationType.EXPIRED_RECALL;
			notificationUser.save();

			//Notify the user that reserved the book
			//Reservation reservation = Reservation.getNext(loan.Loanable.Title.TitleId, true);

			//if (reservation != null)
			//{
			//	Notification notificationUser = new Notification();
			//	User ReservedUser = User.getUserByUserId(reservation.User.UserId);
			//	notification.Recipient = ReservedUser;
			//	notification.Message = string.Format("A borrower has failed to return the book ({0}) you reserved. We are sorry for the inconvenience.", loan.Loanable.Title);
			//	notification.Type = NotificationType.EXPIRED_RECALL;
			//	notification.save();
			//}
		}

        
    }
}
